#include <iostream>
#include <ranges>
#include <vector>
#include <string>
#include <algorithm>
#include <numeric>

// 帮助函数：打印range
// 注意：ranges的view不是const的，所以不能使用const引用
template<std::ranges::input_range Range>
void print_range(Range&& r, const std::string& label) {
    std::cout << "  " << label << ": ";
    for (const auto& elem : r) {
        std::cout << elem << " ";
    }
    std::cout << '\n';
}

// 自定义view，将每个元素加上一个值
struct add_view_fn {
    constexpr auto operator()(std::ranges::viewable_range auto&& r, int val) const {
        return std::forward<decltype(r)>(r) 
             | std::views::transform([val](auto&& elem) { return elem + val; });
    }
};

// 创建自定义view的对象
constexpr add_view_fn add_view{};

void demonstrate_ranges() {
    std::cout << "  C++20 范围库(Ranges)演示:\n\n";
    
    // 创建一个基本容器
    std::vector<int> nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    print_range(nums, "原始数据");
    
    // 1. 基本的范围适配器
    std::cout << "\n  基本的范围适配器:\n";
    
    // 使用filter筛选偶数
    auto even = nums | std::views::filter([](int n) { return n % 2 == 0; });
    print_range(even, "偶数");
    
    // 使用transform转换元素
    auto squared = nums | std::views::transform([](int n) { return n * n; });
    print_range(squared, "平方值");
    
    // 使用take获取前5个元素
    auto first_five = nums | std::views::take(5);
    print_range(first_five, "前5个元素");
    
    // 使用drop跳过前3个元素
    auto skip_three = nums | std::views::drop(3);
    print_range(skip_three, "跳过前3个元素");
    
    // 2. 组合多个范围适配器
    std::cout << "\n  组合范围适配器:\n";
    
    // 跳过前3个元素，取接下来的4个，然后将它们翻倍
    auto combined = nums
                  | std::views::drop(3)
                  | std::views::take(4)
                  | std::views::transform([](int n) { return n * 2; });
    print_range(combined, "跳过前3个，取4个，翻倍");
    
    // 筛选偶数，取前3个，然后计算平方
    auto combined2 = nums
                   | std::views::filter([](int n) { return n % 2 == 0; })
                   | std::views::take(3)
                   | std::views::transform([](int n) { return n * n; });
    print_range(combined2, "前3个偶数的平方");
    
    // 3. 反向和元素访问
    std::cout << "\n  反向和元素访问:\n";
    
    // 反向遍历
    auto reversed = nums | std::views::reverse;
    print_range(reversed, "反向");
    
    // 反向遍历，然后只取奇数索引的元素
    auto reversed_odd_indices = nums
                              | std::views::reverse
                              | std::views::filter([i = 0](int) mutable { return i++ % 2 == 1; });
    print_range(reversed_odd_indices, "反向后的奇数索引元素");
    
    // 4. 使用范围工厂函数
    std::cout << "\n  范围工厂函数:\n";
    
    // iota生成连续的数列
    auto sequence = std::views::iota(1, 11);  // 1到10
    print_range(sequence, "iota(1, 11)");
    
    // 无限序列，加上take限制数量
    auto inf_seq = std::views::iota(1) | std::views::take(10);  // 前10个正整数
    print_range(inf_seq, "无限序列的前10个");
    
    // 重复值（C++20不支持repeat，这里使用iota模拟）
    // 注意：std::views::repeat是C++23的特性，C++20中需要手动实现
    std::vector<int> repeated_vec(5, 42);
    print_range(repeated_vec, "42重复5次");
    
    // 5. 复杂组合和自定义视图
    std::cout << "\n  复杂组合和自定义视图:\n";
    
    // 复杂组合：生成前100个自然数，过滤出3的倍数，转换为平方值，取前10个
    auto complex = std::views::iota(1, 101)
                 | std::views::filter([](int n) { return n % 3 == 0; })
                 | std::views::transform([](int n) { return n * n; })
                 | std::views::take(10);
    print_range(complex, "3的倍数的平方的前10个");
    
    // 使用自定义视图 - 将每个元素加上10
    // 注意：管道操作符需要正确的语法
    auto added = add_view_fn{}(nums, 10);
    print_range(added, "每个元素加10");
    
    // 6. 惰性求值的例子
    std::cout << "\n  惰性求值:\n";
    
    std::cout << "  计算前5个10的倍数的总和:\n";
    auto multiplies_of_ten = std::views::iota(1)
                           | std::views::transform([](int n) { 
                                 std::cout << "  转换: " << n << " -> " << n * 10 << '\n';
                                 return n * 10; 
                             })
                           | std::views::take(5);
    
    // 直到这里计算才会发生
    // 注意：ranges的迭代器与std::accumulate不兼容，使用ranges::fold_left或手动累加
    int sum = 0;
    for (int val : multiplies_of_ten) {
        sum += val;
    }
    std::cout << "  总和: " << sum << '\n';
    
    // 7. 字符串处理示例
    std::cout << "\n  字符串处理:\n";
    
    std::vector<std::string> words = {"hello", "ranges", "in", "C++20", "are", "awesome"};
    
    // 筛选长度大于4的单词
    auto long_words = words 
                    | std::views::filter([](const std::string& s) { return s.length() > 4; });
    print_range(long_words, "长度>4的单词");
    
    // 将每个单词转为大写(仅输出，不修改原始数据)
    auto uppercase_words = words 
                         | std::views::transform([](std::string s) {
                               for (char& c : s) c = std::toupper(c);
                               return s;
                           });
    print_range(uppercase_words, "大写单词");
    
    // 原始数据保持不变
    print_range(words, "原始单词");
} 